package org.ljf.service.impl;

import org.ljf.dao.Seckill;
import org.ljf.dao.SuccessKilled;
import org.ljf.dto.Exposer;
import org.ljf.dto.SecKillEcution;
import org.ljf.exception.RepeatKillException;
import org.ljf.exception.SecKillCloseException;
import org.ljf.exception.SecKillException;
import org.ljf.mapper.SeckillMapper;
import org.ljf.mapper.SuccessKilledMapper;
import org.ljf.service.SeckillService;
import org.ljf.stateEnum.SecKillStateEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;

/**
 * @创建人 lIUJF
 * @创建时间 2018/12/20
 * @描述:
 * @component, 不知道dao/service/controller，则统一使用这个。
 */
@Service
@Transactional(readOnly = true)
public class SecKillServiceImpl implements SeckillService {
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	@Autowired //Resource //
	private SeckillMapper seckillMapper;
	@Autowired
	private SuccessKilledMapper successKilledMapper;
	//加盐，混淆md5
	private final String salt = "asdasdasdasd235436#$&$%&$%&@!@#";

	@Override
	public List<Seckill> getAllSecKiller(){
		List<Seckill> seckills = seckillMapper.selectAll();
		return seckills;
	}

	@Override
	public Seckill getById(long secKillId){
		Seckill seckill = seckillMapper.selectByPrimaryKey(secKillId);

		return seckill;
	}

	@Override
	public Exposer expoertSecKillUrl(long secKillId){
		/**
		 * 优化点，缓存优化
		 * get from cache
		 */
		Seckill seckill = seckillMapper.selectByPrimaryKey(secKillId);
		if (seckill == null) {
			return new Exposer(false, secKillId);
		}
		Date startTime = seckill.getStartTime();
		Date endTime = seckill.getEndTime();
		//系统当前时间
		Date nowTime = new Date();
		if (nowTime.getTime() < startTime.getTime() || nowTime.getTime() > endTime.getTime()) {
			return new Exposer(false, secKillId, nowTime.getTime(), startTime.getTime(), endTime.getTime());
		}
		String md5 = getMd5(secKillId);
		return new Exposer(true, md5, secKillId);
	}


	/**
	 * 使用注解控制事务方法的优点：
	 * 1，开发团队达成一致约定，明确标注事务方法额编程风格
	 * 2，保证事务方法的执行时间尽可能短，不要穿插其他网络操作rpc/http请求或剥离事务方法外部
	 * 3,不是所有方法都需要事务，如只有一条修改操作，只读操作不需要事务控制。
	 */
	@Override
	@Transactional(readOnly = false)
	public SecKillEcution executeKill(String md5, long secKillId, long userPhone){
		try {
			if (StringUtils.isEmpty(md5) || !md5.equals(getMd5(secKillId))) {
				throw new SecKillException("secKill data rewrite");
			}
			//执行秒杀逻辑
			int i = seckillMapper.reduceNumber(secKillId, new Date());
			if (i <= 0) {
				throw new SecKillCloseException("secKill is closed");
			} else {
				//记录购买行为
				SuccessKilled successKilled = new SuccessKilled();
				successKilled.setUserPhone(userPhone);
				successKilled.setSeckillId(secKillId);
				successKilled.setCreateTime(new Date());
				int insert = successKilledMapper.insertSuccessKilled(secKillId,userPhone);
				if (insert <= 0) {
					//重复秒杀
					throw new RepeatKillException("seckill repeated");
				} else {//秒杀成功
					successKilled = successKilledMapper.selectByPrimaryKey(successKilled);
					return new SecKillEcution(secKillId, SecKillStateEnum.SUCCESS, successKilled);
				}
			}
		} catch (SecKillCloseException e1) {
			throw e1;
		} catch (RepeatKillException e2) {
			throw e2;
		} catch (Exception e) {
			e.printStackTrace();
			logger.error(e.getMessage(), e);
			//所有编译期异常转化为运行期异常
			throw new SecKillException("secKill inner error" + e.getMessage());
		}
	}


	private String getMd5(long secKillId){
		String base = secKillId + "/" + salt;
		String md5 = DigestUtils.md5DigestAsHex(base.getBytes());
		return md5;
	}
}
